﻿// This software is the confidential and proprietary information of NetBay.
// Such confidential information should not be disclosed.
// NetBay copyright(c) 2012

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using Rio.Framework.Pages.AppCode.Enums;
using Rio.Framework.WCFService.RioWcfServices;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.DragDrop;
using Telerik.Windows.Controls.GridView;
using Telerik.Windows.Controls.TreeView;

namespace Rio.Framework.Pages.Helpers.DragDrop
{
    /// <summary>
    ///   Provides row (item) reoder capabilities to RadGridView
    /// </summary>
    public partial class RowReorderBehavior
    {
        #region Events

        public static event EventHandler<BeginningDragEventArgs> BeginningDrag;
        public static event EventHandler<DragStartedEventArgs> DragStarted;

        #endregion

        #region Fields

        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled",
                                                typeof (bool),
                                                typeof (RowReorderBehavior),
                                                new PropertyMetadata(false));

        private static AppDisplayMode _mode;
        private RadGridView associatedObject;

        private object currentDropItem;
        private DropPosition currentDropPosition;
        private TreeViewDragCue dragCue;

        #endregion

        #region Properties

        /// <summary>
        ///   AssociatedObject Property
        /// </summary>
        public RadGridView AssociatedObject
        {
            get { return associatedObject; }
            set { associatedObject = value; }
        }

        #endregion

        //public static event EventHandler<CancelEventArgs> EndingDrag;
        //public static event EventHandler<EventArgs> DragEnded;

        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool) obj.GetValue(IsEnabledProperty);
        }

        public static void SetIsEnabled(DependencyObject obj, bool value, AppDisplayMode mode)
        {
            RowReorderBehavior behavior = new RowReorderBehavior();

            _mode = mode;

            behavior.AssociatedObject = obj as RadGridView;

            if (value)
            {
                behavior.Initialize();
            }
            else
            {
                behavior.CleanUp();
            }
            obj.SetValue(IsEnabledProperty, value);
        }

        // Using a DependencyProperty as the backing store for IsEnabled.  This enables animation, styling, binding, etc...

        protected virtual void Initialize()
        {
            AssociatedObject.RowLoaded +=
                AssociatedObject_RowLoaded;
            AssociatedObject.SetValue(RadDragAndDropManager.AllowDropProperty, true);
            SubscribeToDragDropEvents();
        }

        protected virtual void CleanUp()
        {
            AssociatedObject.RowLoaded -= AssociatedObject_RowLoaded;
            AssociatedObject.SetValue(RadDragAndDropManager.AllowDropProperty, false);
            UnsubscribeFromDragDropEvents();
            // uninitialize drag and grop for all rows
        }

        private void AssociatedObject_RowLoaded(object sender, Telerik.Windows.Controls.GridView.RowLoadedEventArgs e)
        {
            if (e.Row is GridViewHeaderRow || e.Row is GridViewNewRow
                || e.Row is GridViewFooterRow)
            {
                return;
            }

            GridViewRow row = e.Row as GridViewRow;
            InitializeRowDragAndDrop(row);
        }

        private void InitializeRowDragAndDrop(GridViewRow row)
        {
            if (row == null)
            {
                return;
            }

            row.SetValue(RadDragAndDropManager.AllowDragProperty, true);
            row.SetValue(RadDragAndDropManager.AllowDropProperty, true);

            RadDragAndDropManager.RemoveDropQueryHandler(row, OnGridViewRowDropQuery);
            RadDragAndDropManager.AddDropQueryHandler(row, OnGridViewRowDropQuery);
        }

        private void SubscribeToDragDropEvents()
        {
            RadDragAndDropManager.AddDropQueryHandler(AssociatedObject, OnDropQuery);
            RadDragAndDropManager.AddDropInfoHandler(AssociatedObject, OnDropInfo);
            RadDragAndDropManager.AddDragQueryHandler(AssociatedObject, OnDragQuery);
            RadDragAndDropManager.AddDragInfoHandler(AssociatedObject, OnDragInfo);
        }

        private void UnsubscribeFromDragDropEvents()
        {
            RadDragAndDropManager.RemoveDropQueryHandler(AssociatedObject, OnDropQuery);
            RadDragAndDropManager.RemoveDropInfoHandler(AssociatedObject, OnDropInfo);
            RadDragAndDropManager.RemoveDragQueryHandler(AssociatedObject, OnDragQuery);
            RadDragAndDropManager.RemoveDragInfoHandler(AssociatedObject, OnDragInfo);
        }

        public virtual DropPosition GetDropPositionFromPoint(Point absoluteMousePosition, GridViewRow row)
        {
            if (row != null)
            {
                Point headerTopPoint = row.TransformToVisual(Application.Current.RootVisual).Transform(new Point());

                double mouseTop = absoluteMousePosition.Y - headerTopPoint.Y;

                if (mouseTop < (row.ActualHeight*2/4))
                {
                    return DropPosition.Before;
                }
                else if (mouseTop > (row.ActualHeight*2/4))
                {
                    return DropPosition.After;
                }
            }

            return DropPosition.Inside;
        }

        private void OnDropQuery(object sender, DragDropQueryEventArgs e)
        {
            if (!(e.Options.Source is GridViewRow))
            {
                return;
            }

            e.QueryResult = true;
            e.Handled = true;
        }

        private void OnDragQuery(object sender, DragDropQueryEventArgs e)
        {
            if (!(e.Options.Source is GridViewRow))
            {
                return;
            }

            RadGridView gridView = sender as RadGridView;

            if (gridView == null)
            {
                return;
            }

            e.QueryResult = InitiateDrag(gridView, e);
            e.Handled = true;
        }

        private void OnDragInfo(object sender, DragDropEventArgs e)
        {
            if (!(e.Options.Source is GridViewRow))
            {
                return;
            }

            RadGridView gridView = sender as RadGridView;

            if (gridView != null)
            {
                IEnumerable draggedItems = e.Options.Payload as IEnumerable ?? gridView.SelectedItems;

                if (e.Options.Status
                    == DragStatus.DragInProgress)
                {
                    dragCue = CreateDragCue();
                    dragCue.ItemsSource = draggedItems;

                    e.Options.DragCue = dragCue;
                }
                else if (e.Options.Status == DragStatus.DragComplete)
                {
                    GridViewRow row =
                        AssociatedObject.ItemContainerGenerator.ContainerFromItem(currentDropItem) as
                        GridViewRow;
                    DropPosition dropPosition = GetDropPositionFromPoint(e.Options.CurrentDragPoint, row);

                    if (_mode == AppDisplayMode.Import || _mode == AppDisplayMode.ImportDirectory)
                    {
                        ObservableCollection<ImageRio> source =
                        new ObservableCollection<ImageRio>((gridView.ItemsSource as IList).Cast<ImageRio>());

                        /*
                        * Create list of items to move
                        */

                        List<ImageRio> imagesToDrop = (from string draggedItem in draggedItems
                                                       from imageRio in source
                                                       where
                                                           draggedItem
                                                           == System.IO.Path.GetFileNameWithoutExtension(imageRio.Name)
                                                       select imageRio).ToList();

                        /*
                        * Get New Index
                        */

                        int newIndex = 0;
                        if (row != null)
                        {
                            newIndex = source.IndexOf(row.Item as ImageRio);

                            if (dropPosition == DropPosition.After)
                            {
                                newIndex++;
                            }

                            newIndex -= imagesToDrop.Count;

                            if (newIndex < 0)
                            {
                                newIndex = 0;
                            }
                        }

                        /*
                        * Remove items
                        */

                        imagesToDrop.ToList().ForEach(i => source.Remove(i));

                        /*
                        * Insert new items
                        */

                        imagesToDrop.Reverse();

                        imagesToDrop.ForEach(i => source.Insert(newIndex, i));

                        gridView.ItemsSource = source;
                    }
                    else
                    {
                        ObservableCollection<ImageRioSearch> source =
                            new ObservableCollection<ImageRioSearch>(
                                (gridView.ItemsSource as IList).Cast<ImageRioSearch>());

                        /*
                        * Create list of items to move
                        */

                        List<ImageRioSearch> imagesToDrop = (from ImageRioSearch draggedItem in draggedItems
                                                             from imageRio in source
                                                             where System.IO.Path.GetFileNameWithoutExtension(draggedItem.OriginalName) == System.IO.Path.GetFileNameWithoutExtension(imageRio.OriginalName)
                                                             select imageRio).ToList();

                        /*
                        * Get New Index
                        */

                        int newIndex = 0;
                        if (row != null)
                        {
                            newIndex = source.IndexOf(row.Item as ImageRioSearch);

                            if (dropPosition == DropPosition.After)
                            {
                                newIndex++;
                            }

                            newIndex -= imagesToDrop.Count;

                            if (newIndex < 0)
                            {
                                newIndex = 0;
                            }
                        }

                        /*
                        * Remove items
                        */

                        imagesToDrop.ToList().ForEach(i => source.Remove(i));

                        /*
                        * Insert new items
                        */

                        imagesToDrop.Reverse();

                        imagesToDrop.ForEach(i => source.Insert(newIndex, i));

                        gridView.ItemsSource = source;
                    }
                }
            }
        }

        private void OnGridViewRowDropQuery(object sender, DragDropQueryEventArgs e)
        {
            if (!(e.Options.Source is GridViewRow))
            {
                return;
            }

            GridViewRow row = sender as GridViewRow;

            if (e.Options.Status
                == DragStatus.DropDestinationQuery)
            {
                currentDropItem = row.Item;
                currentDropPosition = GetDropPositionFromPoint(e.Options.CurrentDragPoint, row);

                e.QueryResult = true;
                e.Handled = true;
            }
        }

        private void OnDropInfo(object sender, DragDropEventArgs e)
        {
            if (!(e.Options.Source is GridViewRow))
            {
                return;
            }

            // Get the drag cu that the TreeView or we have created
            TreeViewDragCue cue = e.Options.DragCue as TreeViewDragCue;
            if (e.Options.Status
                == DragStatus.DropPossible)
            {
                // Set a suitable text:
                GridViewRow row =
                    AssociatedObject.ItemContainerGenerator.ContainerFromItem(currentDropItem) as GridViewRow;
                DropPosition fff = GetDropPositionFromPoint(e.Options.CurrentDragPoint, row);

                cue.DragActionContent = String.Format("{0} ", Enum.GetName(typeof (DropPosition), fff));

                if (_mode == AppDisplayMode.Import
                    || _mode == AppDisplayMode.AddDocument)
                {
                    cue.DragTooltipContent =
                        System.IO.Path.GetFileNameWithoutExtension((currentDropItem as ImageRio).Name);
                }
                else
                {
                    cue.DragTooltipContent =
                        System.IO.Path.GetFileNameWithoutExtension((currentDropItem as ImageRioSearch).Name);
                }

                cue.IsDropPossible = true;
            }
            else if (e.Options.Status
                     == DragStatus.DropImpossible)
            {
                cue.DragActionContent = null;
                cue.IsDropPossible = false;
            }
        }

        private bool InitiateDrag(RadGridView gridView, DragDropQueryEventArgs dragDropArgs)
        {
            List<string> formatItemsToDrag = null;

            if (_mode == AppDisplayMode.Import
                || _mode == AppDisplayMode.AddDocument)
            {
                formatItemsToDrag =
                    gridView.SelectedItems.Cast<ImageRio>().Select(
                        (i, e) => System.IO.Path.GetFileNameWithoutExtension(i.Name)).ToList();
            }
            else
            {
                formatItemsToDrag =
                    gridView.SelectedItems.Cast<ImageRioSearch>().Select(
                        (i, e) => System.IO.Path.GetFileNameWithoutExtension(i.Name)).ToList();
            }

            List<object> itemsToDrag = gridView.SelectedItems.ToList();
            BeginningDragEventArgs eventArgs = new BeginningDragEventArgs(gridView, itemsToDrag);

            OnBeginningDrag(eventArgs);

            if (!eventArgs.Cancel)
            {
                dragDropArgs.Options.Payload = formatItemsToDrag;

                OnDragStarted(new DragStartedEventArgs(gridView, itemsToDrag));
            }

            return !eventArgs.Cancel;
        }

        protected virtual void OnBeginningDrag(BeginningDragEventArgs args)
        {
            if (BeginningDrag != null)
            {
                BeginningDrag(this, args);
            }
        }

        protected virtual void OnDragStarted(DragStartedEventArgs args)
        {
            if (DragStarted != null)
            {
                DragStarted(this, args);
            }
        }

        private TreeViewDragCue CreateDragCue()
        {
            TreeViewDragCue cue = new TreeViewDragCue();
            cue.Style = GetDragCueStyle(AssociatedObject);
            cue.DragTooltipContentTemplate = GetDragCueTooltipContentTemplate(AssociatedObject);
            cue.DragActionContentTemplate = GetDragCueActionContentTemplate(AssociatedObject);

            return cue;
        }
    }
}